package com.yanqu.road.server.cross3server.conn;

import com.yanqu.road.NettyMgr;
import com.yanqu.road.connect.YanQuConnection;
import com.yanqu.road.define.YanQuNettyDefine;
import com.yanqu.road.entity.servercenter.ChannelServerInfo;
import com.yanqu.road.entity.servercenter.ProcessInfo;
import com.yanqu.road.logic.bussiness.DaoHelper;
import com.yanqu.road.logic.config.ChannelConfig;
import com.yanqu.road.logic.helper.CrossChannelHelper;
import com.yanqu.road.message.YanQuMessage;
import com.yanqu.road.pb.server.LoadProto;
import com.yanqu.road.server.CrossBaseServer;
import com.yanqu.road.server.CrossBattleServer;
import com.yanqu.road.server.protocol.ChannelProtocol;
import com.yanqu.road.utils.ConfigHelper;
import com.yanqu.road.utils.ServerType;
import com.yanqu.road.utils.YanQuMessageUtils;
import com.yanqu.road.utils.net.CrossNetConfigHelper;
import com.yanqu.road.utils.net.ServerNetConfig;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.net.InetSocketAddress;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class Cross3ConnSet {

    private static Logger logger = LogManager.getLogger(Cross3ConnSet.class);
    private static Map<Integer, CrossServerConnectionGroup> allChannelConnectSetMap = new ConcurrentHashMap<>();
    private static ServerNetConfig cross2Xml;

    public static boolean init(int serverIndex) {
        try {
            //初始化
            initSelf(serverIndex);
            //连接所有跨区域服
            connectChannelServer();
        } catch (Exception e) {
            logger.error(e);
            return false;
        }
        return true;
    }

    private static void connectChannelServer() {
        long crossServerId = CrossBaseServer.getInstance().getServerId();
        if (!CrossChannelHelper.isCross3(crossServerId)) {
            return;
        }

        // 先检查有没有数据库连接配置
        String dbParam = ChannelConfig.CHANNEL_CENTER_DB_PARAM;
        if ("0".equals(dbParam)) {
            logger.info("[ ChannelConfig.CHANNEL_CENTER_DB_PARAM ] is zero!");
            return;
        }
        int appointChannelServerId = (int) CrossChannelHelper.getAppointChannelServerId(crossServerId);
        ChannelServerInfo channelServerInfo = appointChannelServerId == 0 ?
                DaoHelper.getTempChannelServerInfoDaoImpl(dbParam).getDefaultChannelServerInfo() :
                DaoHelper.getTempChannelServerInfoDaoImpl(dbParam).getChannelServerInfo(appointChannelServerId);
        if (channelServerInfo != null) {

            Map<Integer, CrossServerConnectionGroup> tmpAllChannelConnectSetMap = new ConcurrentHashMap<>();
            for (ProcessInfo processInfo : channelServerInfo.getProcessInfoList()) {
                if (processInfo.getServerName().equals("channel_server")) {
                    CrossBattleServer.getTimerExecutorService().execute(() -> {
                        CrossServerConnectionGroup connectionGroup = connectChannelServer(processInfo);
                        synchronized (tmpAllChannelConnectSetMap) {
                            tmpAllChannelConnectSetMap.put(channelServerInfo.getChannelServerId(), connectionGroup);
                        }
                    });
                }
            }
            allChannelConnectSetMap = tmpAllChannelConnectSetMap;
        }
    }

    private static CrossServerConnectionGroup connectChannelServer(ProcessInfo info) {
        int serverId = info.getServerId();
        int serverType = ServerType.SERVER_CHANNEL;
        ServerNetConfig serverNetConfig = new ServerNetConfig(serverId, info.getName(), info.getAddress(), info.getPort(), info.getAdminPort());
        InetSocketAddress address = new InetSocketAddress(serverNetConfig.getAddress(), serverNetConfig.getPort());
        CrossServerConnectionGroup connectionGroup = new CrossServerConnectionGroup(address, null, YanQuNettyDefine.LINK_COUNT_MAX,
                serverNetConfig, serverType);
        boolean hasFailed = false;
        for (int i = 0; i < YanQuNettyDefine.LINK_COUNT_MAX; i++) {
            try {
                YanQuConnection connection = connectionGroup.connect(i);
                if (connection == null) {
                    logger.error("connect " + serverNetConfig.toString() + " , i = " + i + " fail. ");
                    hasFailed = true;
                    continue;
                }
                connection.getChannel().attr(NettyMgr.LINKED_CLIENT).set(connectionGroup);
                sendRegisterServer(connection, i, serverType);
                connection.setLastHeartTime(System.currentTimeMillis());
            } catch (Exception e) {
                hasFailed = true;
                logger.error("connect " + serverNetConfig.toString() + " , i = " + i + " error. ", e);
            }
        }
        if (hasFailed) {

        } else {
            logger.info("connect success：" + serverNetConfig.toString());
        }
        return connectionGroup;
    }

    private static void initSelf(int serverIndex) {
        cross2Xml = CrossNetConfigHelper.getServerNetConfig(ServerType.SERVER_CROSS_2, serverIndex);
    }

    public static void sendRegisterServer(YanQuConnection connection, int i, int serverType) {
        int sendCode = ChannelProtocol.N_REGISTER;
        LoadProto.LoadChannelMsg.Builder msg = writeProto(ConfigHelper.getLong("serverId"), cross2Xml, 0, serverType, i, ConfigHelper.getInt("channelId"));
        YanQuMessage packet = YanQuMessageUtils.buildMessage(sendCode, msg);
        connection.send(packet);
    }

    public static void checkConn() {
        for (CrossServerConnectionGroup connectionGroup : allChannelConnectSetMap.values()) {
            connectionGroup.keepAlive();
        }
    }

    public static LoadProto.LoadChannelMsg.Builder writeProto(long serverId, ServerNetConfig configXml, int load, int serverType, int linkIndex, int channelId) {
        LoadProto.LoadChannelMsg.Builder msg = LoadProto.LoadChannelMsg.newBuilder();
        msg.setServerId(serverId);
        msg.setServerIndex(configXml.getServerIndex());
        msg.setServerName(configXml.getName() == null ? "" : configXml.getName());
        msg.setAddress(configXml.getAddress() == null ? "" : configXml.getAddress());
        msg.setPort(configXml.getPort());
        msg.setLoad(load);
        msg.setType(serverType);
        msg.setConnTimes(0);
        msg.setLinkIndex(linkIndex);
        msg.setChannelId(channelId);
        return msg;
    }

    public static void setChannelConnSetCheckTime(int index, int serverType, int id) {
        CrossServerConnectionGroup group = allChannelConnectSetMap.get(id);
        if (group != null) {
            group.receiveHearBeat(index);
            logger.info("write connectionTime, ServerType: {} ,id: {}, index : {}", serverType, id, index);
        }
    }

    public static void send(long serverId, YanQuMessage packet) {
        int intServerId = (int) serverId;
        CrossServerConnectionGroup group = allChannelConnectSetMap.get(intServerId);
        if (group != null) {
            group.send(packet);
        } else {
            logger.error("can not find channelServer connection, channelServerId={}", serverId);
        }
    }

    public static void sendToAll(YanQuMessage packet) {
        if (allChannelConnectSetMap != null) {
            if (allChannelConnectSetMap.size() == 0) {
                logger.error("can not find channelServer connection, no connection exist!");
                return;
            }
            for (long serverId : allChannelConnectSetMap.keySet()) {
                send(serverId, packet);
            }
        }
    }

}
